'''
Created on Jul 16, 2010

@author: riche
'''

from ft.framework import application, component
from ft.framework.net_io import *
from ft.framework.quorum import gen_quorum
from ft.directory import cameras
from ft.apps.messages import agree_msgs, client_msgs

class AgreeAbstractionComp(component.Implementation):
    
    def __init__(self, name, node_name):
        component.Implementation.__init__(self, name)
        self._node_name = node_name
        self.__curr_seq_no__ = 0
        self.__curr_cp_state__ = 0
    
    def handle_request(self, msg):
        print('Processing this: ' + msg)
        try:
            client_msgs.Message(msg)
            cp = 0
            if self._node_name == cameras.AGREE0_NAME:
                if self.__curr_seq_no__ % 10 == 0:
                    cp = 1
                message = agree_msgs.CommMsg(self.__curr_seq_no__, msg, cp)
                self.send_out('out', (cameras.BCAST_AGREES_NAME, message.get_body()))
                if cp == 1:
                    print('Requesting checkpoint')
                exec_message = agree_msgs.ExecMsg(self.__curr_seq_no__, msg, cp)
                #self.send_out('out', (cameras.QA_NAME, exec_message.get_body()))
                self.send_out('out', (cameras.BCAST_SERVERS_NAME, exec_message.get_body()))
                self.__curr_seq_no__ += 1
            else:
                message = agree_msgs.Message(msg)
                if message.cmd == agree_msgs.FTCMD_COM:
                    new_message = agree_msgs.ExecMsg(message.seq_no, message.internals, message.cp)
                    #self.send_out('out', (cameras.QA_NAME,new_message.get_body()))
                    self.send_out('out', (cameras.BCAST_SERVERS_NAME,new_message.get_body()))
        except Exception as err:
            print(err)
            if self._node_name == cameras.AGREE0_NAME:
                message = agree_msgs.Message(msg)
                if message.cmd == agree_msgs.FTCMD_CP:
                    self.__curr_cp_state__ = int(message.internals)
            else:
                self.send_out('out', (cameras.AGREE0_NAME, msg))
                
class QPrime(component.Implementation):
    
    def check_msg(self, msg):
        print('Received: ' + str(msg))
        message = agree_msgs.Message(msg)
        if message.cmd == agree_msgs.FTCMD_FETCH:
            self.send_out('out', msg)
        else:
            self.send_out('quorum', msg)

class Agreement(application.Application):
    '''
    ACFT Agreement node implementation
    '''

    def __init__(self):
        '''
        Constructor
        '''
        application.Application.__init__(self)
        
    def setup(self):
        
        quorum_comp = gen_quorum.GenericQuorum('quorum_comp', cameras.local_directory.server_q_thresh) 
        self.create_component(quorum_comp, [('in', 'process_msg'), ('q_found', '__OUT__')])
        
        qprime = QPrime('qprime')
        self.create_component(qprime, [('in', 'check_msg'), ('out', '__OUT__'), ('quorum', '__OUT__')])
                
        agree_comp = AgreeAbstractionComp('agree_comp', self._node_name)
        self.create_component(agree_comp, [('in', 'handle_request'), ('out', '__OUT__')])
        
        nr = net_reader.NetReaderComponent(self._node_name, cameras.local_directory)
        nr2name = '{}{}'.format(self._node_name, cameras.FEEDBACK)
        nr2 = net_reader.NetReaderComponent(nr2name, cameras.local_directory)
        nw = net_writer.NetWriterComponent('netout', self._node_name, cameras.local_directory)
        
        self.add_components([nr, nw, nr2])
        
        nr2_to_qprime = self.create_connection((nr2name, 'out'), ('qprime', 'in'))
        agree_to_nw = self.create_connection(('agree_comp', 'out'),('netout','in'))
        
        nr_to_agree = self.create_connection((self._node_name, 'out'), ('agree_comp', 'in'))
        qprime_to_agree = self.create_connection(('qprime', 'out'), ('agree_comp', 'in'))
        qprime_to_quorum = self.create_connection(('qprime', 'quorum'), ('quorum_comp', 'in'))
        quorum_to_agree = self.create_connection(('quorum_comp', 'q_found'), ('agree_comp', 'in'))

        nr_thread = application.CompThread(nr, [nr_to_agree], True)
        nr2_thread = application.CompThread(nr2, [nr2_to_qprime], True)
        nw_thread = application.CompThread(nw, [agree_to_nw])
        agree_thread = application.CompThread(agree_comp, [nr_to_agree, qprime_to_agree, quorum_to_agree, agree_to_nw])
        qprime_thread = application.CompThread(qprime, [qprime_to_quorum, qprime_to_agree, nr2_to_qprime])
        quorum_thread = application.CompThread(quorum_comp, [qprime_to_quorum, quorum_to_agree])

        self.add_threads([nr_thread, nr2_thread, nw_thread, agree_thread, qprime_thread, quorum_thread])
        
if __name__ == '__main__':
    agree = Agreement()
    agree.parse_opts()
    agree.setup()
    agree.execute()
